HP200LX Filer protocol
----------------------

Rodrigo Serra, 2002
Pavel Zampach, 2003-2005


Hardware layer
--------------
No handshaking, either hardware (RTS/CTS) nor software (Xon/Xoff),
is used. HP200LX and host computer can be connected by 3-wire
cable (RX-TX, TX-RX, GND-GND). Baud rate is 2400 - 115200 Bd.


Packet layer
------------
For every packet send another is recieved. All the packets have the following
structure:

Transmit:
packet signature              CMD  CNT            DATA  end       CRC 
0x16 0x16 0x16 0x10 0x02 0x01 ???  ???  0x01 0x02 ...   0x10 0x03 Lo   Hi
*    *    *    *    *				        *         *    *

Receive:
packet signature              CMD  CNT            DATA  end       CRC 
0x16 0x16 0x16 0x10 0x02 0x01 ???  ???  0x81 0x02 ...   0x10 0x03 Lo   Hi
*    *    *    *    * 					*         *    *

CMD    command requested (see commands)
CNT    count of packet. Maximal value is 0xff, next one is 0x00
DATA   data send to/from the palmtop
*      indicate no CRC calculation for this byte

CRC is constructed with the calculating this for every byte except the 
bytes marked by the * symbol. The following code calculate CRC for one 
byte. If the CRC is calulated, every byte with value 0x10 is send/recieve
TWICE!

int i, polynomial = 0xa001;
crc^=b;
for(i=0;i<8;i++) crc = (crc >> 1) ^ ((crc & 1)!=0 ? polynomial : 0);


Command layer
-------------
The following explanation of packet only show the command and DATA part of 
the packet. Data=null means no bytes transmited.


      CONNECT
CMD=CMD_CONNECT_SERVER
CNT=0
T: DATA=null;
R: DATA={0,0};


      DISCONNECT
CMD=CMD_DISCONNECT_SERVER
CNT=0
T: DATA=null;
R: DATA={0,0};


      GET ACTIVE DISK
CMD=CMD_GET_ACTIVEDISK
T: DATA={0,0};
R: DATA={0,0,0,0,DiskChar,0};


      SET ACTIVE DISK
CMD=CMD_SET_DISK
T: DATA={DiskChar, 0};
R: DATA={0,0,0,0,0,0};


      GET DISK INFO
CMD=CMD_GET_DISKINFO
T: DATA={0,0};
R: DATA={0,0,0,0,volume[].length()%256,volume[].length()/256,diskInfo()};


      GET DISK VECTOR
CMD=CMD_GET_DISKVECTOR
T: DATA={0,0};
R: DATA={0,0,0,0,vector[].length()%256,vector[].length()/256,vector[],0,0,0,0};
Vector is null-terminated string with chars of defined disks


      GET ACTIVE DIR
CMD=CMD_GET_ACTIVEDIR
T: DATA={DiskChar, 0};
R: DATA={0,0,0,0,DirectoryName[].length()%256,DirectoryName[].length()/256,DirectoryName[],0,0,0,0};


      SET ACTIVE DIR
CMD=CMD_SET_DIR
T: DATA={DirectoryName[].length()%256,DirectoryName[].length()/256,DirectoryName[],0,0};
R: DATA={0,0,0,0,0,0};


      CHECK FILE OR DIRECTORY
CMD=CMD_CHECK_FILE
T: DATA={File/DirName[].length()%256,File/DirName[].length()/256,File/DirName[],0,0};
R: DATA={0,0,0,0,aaa,0};
aaa = 0   file or directory not exists
aaa = 1   file exists
aaa = 2   directory exists (directory name without trailing backslash)


      GET FILE ATTRIBUTE
CMD=CMD_GET_FILEATTR
T: DATA={FileName[].length()%256,FileName[].length()/256,FileName[],0,0};
R: DATA={0,0,0,0,FileAttr,0};


      SET FILE ATTRIBUTE
CMD=CMD_SET_FILEATTR
T: DATA={FileName[].length()%256,FileName[].length()/256,FileName[],FileAttr,0};
R: DATA={0,0,0,0,0,0};

      
      DELETE DIRECTORY
CMD=CMD_DEL_DIR
T: DATA={DirectoryName[].length()%256,DirectoryName[].length()/256,DirectoryName[],0,0};
R: DATA={0,0,0,0,0,0};


      MAKE DIRECTORY
CMD=CMD_MAKE_DIR
T: DATA={DirectoryName[].length()%256,DirectoryName[].length()/256,DirectoryName[],0,0};
R: DATA={0,0,0,0,0,0};


      DELETE FILE
CMD=CMD_DEL_FILE
T: DATA={FileName[].length()%256,FileName[].length()/256,FileName[],0,0};
R: DATA={0,0,0,0,0,0};


      RENAME FILE OR DIRECTORY
CMD=CMD_REN_FILE
T: DATA={FileNameFrom[].length()%256,FileNameFrom[].length()/256,FileNameFrom[],0,0,FileNameTo[].length()%256,FileNameTo[].length()/256,FileNameTo[],0,0};
R: DATA={0,0,0,0,0,0};


      LIST DIRECTORY
CMD=CMD_ASK_DIR
T: DATA={DirectoryName[].length()%256,DirectoryName[].length()/256,DirectoryName[],0,0};
R: DATA={0,0,0,0,0,0};

CMD=CMD_GET_DIR
T: DATA=null;
R: DATA={0,0,DirEntry[].length()%256,dirEntry[].length()/256,dirEntry,aaa,0,0,0};
aaa=1  Valid dir item
aaa=0  End of dir items


      GET FILE
CMD=CMD_RESET_FILE
T: DATA={FileName[].length()%256,FileName[].length()/256,FileName[],0,0};
R: DATA={0,0,0,0,0,0};

CMD=CMD_INIT_GET
T: DATA=null;
R: DATA={0,0,0,0,0,0};
this command is used in original protocol, but can be omitted without penalty

CMD=CMD_GET_DATA
T: DATA={0,0,Buffer[].length()%256,Buffer[].length()/256};
R: DATA={0,0,0,0,Buffer[].length()%256,Buffer[].length()/256,Buffer[]};
last packet when T.Buffer.length() != R.Buffer.length()

CMD=CMD_CLOSE_FILE
T: DATA={0,0};
R: DATA={0,0,0,0,0,0};


      SEND FILE
CMD=CMD_CREATE_FILE (file MUST NOT exist)
 or
CMD=CMD_REWRITE_FILE (if file exists, it is rewritten)
T: DATA={FileName[].length()%256,FileName[].length()/256,FileName[],0,0};
R: DATA={0,0,0,0,0,0};

CMD=CMD_SEND_DATA
T: DATA={0,0,Buffer[].length()%256,Buffer[].length()/256,Buffer[]};
R: DATA={0,0,0,0,Buffer[].length()%256,Buffer[].length()/256};
   
CMD=CMD_CLOSE_FILE
T: DATA={0,0};
R: DATA={0,0,0,0,0,0};


       GET FILE TIME/DATE
CMD=CMD_GET_FILETIME
T: DATA={0,0};
R: DATA={0,0,0,0,timeStamp%256,timeStamp/256,dateStamp%256,dateStamp/256};
File must be opened by appropriate command (CMD_CREATE_FILE, CMD_REWRITE_FILE
CMD_RESET_FILE)!


      SET FILE TIME/DATE
CMD=CMD_SET_FILETIME
T: DATA={0,0,timeStamp%256,timeStamp/256,dateStamp%256,dateStamp/256};
R: DATA={0,0,0,0,0,0};
File must be opened by appropriate command (CMD_CREATE_FILE, CMD_REWRITE_FILE
CMD_RESET_FILE)!


      GET POSITION OF READ/WRITE POINTER
CMD=CMD_GET_FILEPOINTER
T: DATA={0,0};
R: DATA={0,0,0,0,aaa,bbb,ccc,ddd};
pointer_position=aaa + (0x100*bbb) + (0x10000*ccc) + (0x100000*ddd)
File must be opened by appropriate command (CMD_CREATE_FILE, CMD_REWRITE_FILE
CMD_RESET_FILE)!
 

      SET POSITION OF READ/WRITE POINTER
CMD=CMD_SET_FILEPOINTER
T: DATA={0,0,0,0,aaa,bbb,ccc,ddd};
R: DATA={0,0,0,0,0,0};
pointer_position=aaa + (0x100*bbb) + (0x10000*ccc) + (0x100000*ddd)
File must be opened by appropriate command (CMD_CREATE_FILE, CMD_REWRITE_FILE
CMD_RESET_FILE)!



Data structures
---------------
PACKET_DATA_SIZE     =0x0800;

Commands
CMD_CLOSE_FILE       =0x01
  command 0x02 probably doesn't exist
CMD_CREATE_FILE      =0x03
CMD_DEL_FILE         =0x04
CMD_REWRITE_FILE     =0x05
CMD_GET_ACTIVEDIR    =0x06
CMD_GET_ACTIVEDISK   =0x07
CMD_CHECK_FILE       =0x08
CMD_GET_DIR          =0x09
CMD_MAKE_DIR         =0x0A
CMD_RESET_FILE       =0x0B
CMD_GET_DATA         =0x0C
CMD_REN_FILE         =0x0D
CMD_DEL_DIR          =0x0E
CMD_SET_FILEPOINTER  =0x0F
CMD_SET_DIR          =0x10
CMD_SET_DISK         =0x11
CMD_ASK_DIR          =0x12
CMD_GET_FILEPOINTER  =0x13
CMD_GET_DISKINFO     =0x14
CMD_SEND_DATA        =0x15
CMD_INIT_GET         =0x16
CMD_GET_FILETIME     =0x17
CMD_SET_FILETIME     =0x18
CMD_GET_FILEATTR     =0x19
CMD_SET_FILEATTR     =0x1A
CMD_GET_DISKVECTOR   =0x1B
CMD_CONNECT_SERVER   =0x40
CMD_DISCONNECT_SERVER=0x41


Structure of dirEntry:

dirEntry[0]          =fileAttr;

dirEntry[1..2]       =(UINT)timeStamp;
timeStamp>>11        =hour;
(timeStamp>>5)&0x3f  =minute;
(timeStamp&0x1f)*2   =seconde;
               
dirEntry[3..4]       =(UINT)dateStamp;
(dateStamp>>9)+1980  =year;
(dateStamp>>5)&0x0f  =month;
timeStamp&0x1f       =day;
               
dirEntry[5..8]       =(UINT)fileSize;

dirEntry[9..21]      =fileName;


Structure of diskInfo

diskInfo[0..10]      =volumeName;
diskInfo[11..14]     =(UINT)freeSpace
